"""
JWT工具类
提供JWT Token的生成、验证和刷新功能
"""
from datetime import datetime, timedelta
import jwt
from flask import current_app
from functools import wraps
from flask import request, jsonify, g

def generate_token(user_id, username, role='student'):
    """
    生成JWT Token
    
    Args:
        user_id: 用户ID
        username: 用户名
        role: 用户角色
    
    Returns:
        dict: 包含access_token和refresh_token的字典
    """
    secret_key = current_app.config.get('JWT_SECRET_KEY', 'dev-secret-key-change-in-production')
    algorithm = current_app.config.get('JWT_ALGORITHM', 'HS256')
    access_token_expires = current_app.config.get('JWT_ACCESS_TOKEN_EXPIRES', 3600)  # 1小时
    refresh_token_expires = current_app.config.get('JWT_REFRESH_TOKEN_EXPIRES', 604800)  # 7天
    
    # 生成Access Token
    access_token_payload = {
        'user_id': user_id,
        'username': username,
        'role': role,
        'type': 'access',
        'exp': datetime.utcnow() + timedelta(seconds=access_token_expires),
        'iat': datetime.utcnow()
    }
    access_token = jwt.encode(access_token_payload, secret_key, algorithm=algorithm)
    
    # 生成Refresh Token
    refresh_token_payload = {
        'user_id': user_id,
        'username': username,
        'type': 'refresh',
        'exp': datetime.utcnow() + timedelta(seconds=refresh_token_expires),
        'iat': datetime.utcnow()
    }
    refresh_token = jwt.encode(refresh_token_payload, secret_key, algorithm=algorithm)
    
    return {
        'access_token': access_token,
        'refresh_token': refresh_token,
        'token_type': 'Bearer',
        'expires_in': access_token_expires
    }

def verify_token(token):
    """
    验证JWT Token
    
    Args:
        token: JWT Token字符串
    
    Returns:
        dict: Token解码后的payload，如果验证失败返回None
    """
    try:
        secret_key = current_app.config.get('JWT_SECRET_KEY', 'dev-secret-key-change-in-production')
        algorithm = current_app.config.get('JWT_ALGORITHM', 'HS256')
        payload = jwt.decode(token, secret_key, algorithms=[algorithm])
        return payload
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None

def get_current_user():
    """
    从请求头中获取当前用户信息
    
    Returns:
        dict: 用户信息，如果未认证返回None
    """
    auth_header = request.headers.get('Authorization')
    if not auth_header:
        return None
    
    try:
        token_type, token = auth_header.split(' ', 1)
        if token_type != 'Bearer':
            return None
        
        payload = verify_token(token)
        if payload and payload.get('type') == 'access':
            return {
                'user_id': payload.get('user_id'),
                'username': payload.get('username'),
                'role': payload.get('role')
            }
    except Exception:
        return None
    
    return None

def require_auth(f):
    """
    装饰器：要求用户认证
    
    Usage:
        @require_auth
        def protected_route():
            user = g.current_user
            return jsonify({'message': f'Hello {user["username"]}'})
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        user = get_current_user()
        if not user:
            return jsonify({
                'status': 'error',
                'message': '未认证，请先登录'
            }), 401
        
        g.current_user = user
        return f(*args, **kwargs)
    
    return decorated_function

def require_role(*roles):
    """
    装饰器：要求特定角色
    
    Usage:
        @require_role('admin', 'teacher')
        def admin_route():
            return jsonify({'message': 'Admin access'})
    """
    def decorator(f):
        @wraps(f)
        @require_auth
        def decorated_function(*args, **kwargs):
            user = g.current_user
            if user['role'] not in roles:
                return jsonify({
                    'status': 'error',
                    'message': '权限不足'
                }), 403
            
            return f(*args, **kwargs)
        return decorated_function
    return decorator

